package tv.dyndns.kishibe.server;

import static com.google.inject.Scopes.SINGLETON;
import static com.google.inject.name.Names.named;

import org.apache.http.HttpVersion;
import org.apache.http.client.HttpClient;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.params.ConnManagerParams;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.openid4java.consumer.ConsumerManager;

import tv.dyndns.kishibe.client.constant.Constant;
import tv.dyndns.kishibe.client.packet.PacketServerStatus;
import tv.dyndns.kishibe.server.database.CachedDatabase;
import tv.dyndns.kishibe.server.database.Database;
import tv.dyndns.kishibe.server.database.DirectDatabase;
import tv.dyndns.kishibe.server.handwriting.Recognizable;
import tv.dyndns.kishibe.server.handwriting.RecognizerZinnia;
import tv.dyndns.kishibe.server.handwriting.ZinniaLibrary;
import tv.dyndns.kishibe.server.handwriting.ZinniaObjectFactory;
import tv.dyndns.kishibe.server.relevance.Downloader;
import tv.dyndns.kishibe.server.sns.SnsClient;
import tv.dyndns.kishibe.server.sns.SnsClients;
import tv.dyndns.kishibe.server.websocket.BroadcastWebSockets;
import tv.dyndns.kishibe.server.websocket.WebSocketServer;

import com.google.gson.Gson;
import com.google.gwt.logging.server.RemoteLoggingServiceImpl;
import com.google.inject.AbstractModule;
import com.google.inject.Provides;
import com.google.inject.Singleton;
import com.google.inject.TypeLiteral;
import com.google.inject.assistedinject.FactoryModuleBuilder;
import com.sun.jna.Native;

public class QMACloneModule extends AbstractModule {
	@Override
	protected void configure() {
		bind(ChatManager.class).in(SINGLETON);
		bind(NormalModeProblemManager.class).in(SINGLETON);
		bind(ThemeModeProblemManager.class).in(SINGLETON);
		bind(GameManager.class).in(SINGLETON);
		bind(ServerStatusManager.class).in(SINGLETON);
		bind(BadUserManager.class).in(SINGLETON);
		bind(PlayerHistoryManager.class).in(SINGLETON);
		bind(VoteManager.class).in(SINGLETON);
		bind(Recognizable.class).to(RecognizerZinnia.class).in(SINGLETON);
		bind(ThemeModeEditorManager.class).in(SINGLETON);
		bind(int.class).annotatedWith(named("webSocketServerPort")).toInstance(
				Constant.WEB_SOCKET_PORT);
		bind(WebSocketServer.class).in(SINGLETON);
		bind(ImageManager.class).in(SINGLETON);
		bind(PrefectureRanking.class).in(SINGLETON);
		bind(RatingDistribution.class).in(SINGLETON);
		bind(CachedDatabase.class).in(SINGLETON);
		bind(Database.class).to(CachedDatabase.class).in(SINGLETON);
		bind(Database.class)
				.annotatedWith(named("DirectDatabase"))
				.to(DirectDatabase.class)
				.in(SINGLETON);
		install(new FactoryModuleBuilder().build(Game.Factory.class));
		install(new FactoryModuleBuilder().build(ComputerPlayer.Factory.class));
		install(new FactoryModuleBuilder().build(PlayerAnswer.Factory.class));
		bind(RemoteLoggingServiceImpl.class).in(SINGLETON);
		bind(ZinniaLibrary.class).toInstance(
				(ZinniaLibrary) Native.loadLibrary("zinnia", ZinniaLibrary.class));
		bind(ZinniaObjectFactory.class).in(SINGLETON);
		bind(SnsClient.class).annotatedWith(named("SnsClients")).to(SnsClients.class);
		bind(Downloader.class).in(SINGLETON);
		bind(new TypeLiteral<BroadcastWebSockets<PacketServerStatus>>() {
		}).toInstance(new BroadcastWebSockets<PacketServerStatus>() {
			@Override
			protected String parse(PacketServerStatus status) {
				return new Gson().toJson(status);
			}
		});
		bind(ConsumerManager.class).in(SINGLETON);
	}

	@SuppressWarnings("unused")
	@Provides
	@Singleton
	private HttpClient providesHttpClient() {
		HttpParams params = new BasicHttpParams();
		ConnManagerParams.setMaxTotalConnections(params, 100);
		HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
		SchemeRegistry schemeRegistry = new SchemeRegistry();
		schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
		ClientConnectionManager cm = new ThreadSafeClientConnManager(params, schemeRegistry);
		return new DefaultHttpClient(cm, params);
	}
}
